/***************************************************************************\
 * The Mattise Kernel														*
 * Copyright 2007 Matthew Iselin											*
 * Licensed under the GPL													*
 *																			*
 * mem.cc																	*
 *																			*
 * Memory management and utility functions.									*
 *																			*
\***************************************************************************/

#include "kernel.h"
#include "pm.h"
#include "heap.h"

// memset, sets a range of memory
void memset( void* ptr, unsigned char dat, int len )
{
	int i;
	char* tmp = (char*) ptr;
	for( i = 0; i < len; i++ )
	{
		*tmp++ = dat;
	}
}

// memcpy, copies a block of data
void* memcpy( void *dest, const void *src, int n )
{
	char *dst=(char*)dest,*source=(char*)src;
	for( ; n ; n-- )
		*dst++ = *source++;
	return dest;
}

/// unified both header parameters into one solid structure. --kmcguire
HEAP g_kheap;

/// modification to support multiple heaps. --kmcguire
void __kheap_init(unsigned int address, unsigned int size, PHEAP heap){
	heap->heap = (struct tkheap*)address;
	heap->heap->flags = 0;
	heap->heap->size = size - sizeof(struct tkheap);
	heap->size = size;
	return;
}

/// original heap function. --kmcguire
void kheap_init(unsigned int address, unsigned int size){
	__kheap_init(address, size, &g_kheap);
}

/// modification to support multiple heaps. --kmcguire
void* __kheap_alloc(unsigned int size, PHEAP heap){
	struct tkheap *ch, *nh;	
	kdbginfo("heap->heap:%u heap->size:%u\n", heap->heap, heap->size);
	for(ch = heap->heap; (unsigned int)ch < ((unsigned int)heap->heap + heap->size); ch = (struct tkheap*)((unsigned int)ch + ch->size + sizeof(struct tkheap))){
		if(ch->flags == 0){
			kdbginfo("free block found: %u\n", ch);
			if(ch->size == size){
				ch->flags = (uint32_t)heap;
				//KMSG(ksprintf(0, "size was equal.\x10"));
				return (void*)((unsigned int)ch + sizeof(struct tkheap));
			}
			if(ch->size > size){
				ch->flags = (uint32_t)heap;

				//KMSG(ksprintf(0, "size was greater.\x10"));
				if((ch->size - sizeof(struct tkheap)) > (size+10)){
				//	KMSG(ksprintf(0, "splitting.\x10"));
					nh = (struct tkheap*)((unsigned int)ch + size + sizeof(struct tkheap));
					nh->size = ch->size - size - sizeof(struct tkheap);
					nh->flags = 0;
					ch->size = size;
				}else{
				//	KMSG(ksprintf(0, "using whole.\x10"));
					ch->size = ch->size;
				}
				return (void*)((unsigned int)ch + sizeof(struct tkheap));
			}
		}else{
			//kdbginfo("found used block: %u of size: %u\n", ch, ch->size);
		}
	}
	kdbgerror("WARNING: HEAP ALLOCATION FAILED!!\n");
	for(;;);
	return 0;
}

/// original heap function. --kmcguire
void* kheap_alloc(unsigned int size){
	return __kheap_alloc(size, &g_kheap);
}

/// modification to support multiple heaps. --kmcguire
void __kheap_free(void *ptr, PHEAP heap){
	struct tkheap *hptr = (struct tkheap*)((uint32_t)ptr - sizeof(struct tkheap));
	hptr->flags = 0;
	return;
}
/// original heap function. --kmcguire
void kheap_free(void *ptr){
	__kheap_free(ptr, &g_kheap);
}

/// FIXME: implement these functions..
void kheap_reclaim(void);

